﻿#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <asm-generic/gpio.h>
#include <linux/delay.h>

struct gpio_desc{
	int gpio;
    char *name;
} ;

static struct gpio_desc gpios[4] = {
    {115, "GPIO4_19", },//A
    {116, "GPIO4_20", },//B
	{117, "GPIO4_21", },//C
    {118, "GPIO4_22", },//D
};
 
static int motor_pin_ctrl[8] = {0x02, 0x03, 0x01, 0x09, 0x08, 0x0c, 0x04, 0x06};
static int motor_index = 0;
static int major = 0;
static struct class *motor_class;
int count = sizeof(gpios)/sizeof(gpios[0]);

void set_motor_pin_value (int index)
{
    int i;
	for(i = 0; i < count; i++)
	{
		gpio_set_value(gpios[i].gpio, motor_pin_ctrl[index] & 1<<i ? 1 : 0);
	}
}

void disable_motor(void)
{
	int i;
	for(i = 0; i < count; i++)
	{
		gpio_set_value(gpios[i].gpio, 0);
	}
}

/* int buf[2];
 * buf[0] = 步进的次数, > 0 : 逆时针步进; < 0 : 顺时针步进
 * buf[1] = mdelay的时间
 */
static ssize_t motor_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    int ker_buf[2];
    int err;
	int step = 0;
    
    err = copy_from_user(ker_buf, buf, size);
    
	if(ker_buf[0] > 0)
	{
		/*clockwise*/
		motor_index = 0;
		for(step = 0; step < ker_buf[0]; step++)
		{
            set_motor_pin_value(motor_index);
		    mdelay(ker_buf[1]);
			motor_index++;
			motor_index = motor_index % 8;
		}
		
	}
	else
	{
		/*counterclockwise*/
		ker_buf[0] = 0 - ker_buf[0];
		motor_index = 7;
		for(step = 0; step < ker_buf[0]; step++)
		{
            set_motor_pin_value (motor_index);
		    mdelay(ker_buf[1]);
			motor_index--;
			motor_index = motor_index < 0 ? 7 : motor_index;
		}
	}
	
	/*after the end,disable motor,save power consumption*/
	disable_motor();

    return 8;
}



/* 定义自己的file_operations结构体 */
static struct file_operations motor_drv_fops = {
	.owner	 = THIS_MODULE,
	.write   = motor_drv_write,
};

/* 在入口函数 */
static int __init motor_drv_init(void)
{
    int err = 0;
	int i;

    for(i = 0; i < count; i++)
	{
	    gpio_request(gpios[i].gpio,gpios[i].name);
		gpio_direction_output(gpios[i].gpio, 0);
	}

	/* 注册file_operations 	*/
	major = register_chrdev(0, "motor_drv", &motor_drv_fops); 

	motor_class = class_create(THIS_MODULE, "motor_class");
	if (IS_ERR(motor_class)) {
          unregister_chrdev(major, "motor");
          return PTR_ERR(motor_class);
	}

	device_create(motor_class, NULL, MKDEV(major, 0), NULL, "motor"); 
	
	return err;
}

/* 有入口函数就应该有出口函数：卸载驱动程序时，就会去调用这个出口函数
 */
static void __exit motor_drv_exit(void)
{
    int i;

	device_destroy(motor_class, MKDEV(major, 0));
	class_destroy(motor_class);
	unregister_chrdev(major, "motor");

    for(i = 0; i < count; i++)
	{
	    gpio_free(gpios[i].gpio);
	}

}


/* 7. 其他完善：提供设备信息，自动创建设备节点                                     */

module_init(motor_drv_init);
module_exit(motor_drv_exit);

MODULE_LICENSE("GPL");


